package com.vinfai.thread.concurrent;

import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggerFactory;

/**
 * Semaphore 是一个计数信号量。从概念上讲，信号量维护了一个许可集。如有必要，在许可可用前会阻塞每一个 acquire()，然后再获取该许可。每个 release() 添加一个许可，从而可能释放一个正在阻塞的获取者。但是，不使用实际的许可对象，Semaphore 只对可用许可的号码进行计数，并采取相应的行动。 
 * Semaphore 通常用于限制可以访问某些资源（物理或逻辑的）的线程数目。
 * @author vinfai
 *
 */
public class SemaphoreTest {
	Logger logger = Logger.getLogger(SemaphoreTest.class);
	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception{
		
		ObjectFactory factory = new MyObjectFactory();
		ObjPool<String> pools = new ObjPool<String>(10, factory);
		
		String t = pools.getObject();
		System.out.println(t);
		String t2 = pools.getObject();
		System.out.println(t2);
		String t3 = pools.getObject();
		String t4 = pools.getObject();
		String t5 = pools.getObject();
		String t6 = pools.getObject();
		String t7 = pools.getObject();
		String t8 = pools.getObject();
		String t9 = pools.getObject();
		String t10 = pools.getObject();
		String t11 = pools.getObject();
		//放回对象
		pools.returnObject(t2);
		pools.returnObject(t);
		//再次取出
		String r3 = pools.getObject();
		System.out.println(r3);
		String r4 = pools.getObject();
		System.out.println(r4);
	}
	
	
}

/**
 * 通过信号量来控制数量
 * @author vinfai
 * 以链表形式存储，通过Semaphore控制对象池的读取操作
 */
class ObjPool<T>{
	private Logger logger = Logger.getLogger(ObjPool.class);
	private int capacity ;
	private Node<T> head ;
	private Node<T> tail;
	private Semaphore semaphore;
	private ReentrantLock lock = new ReentrantLock();//锁机制
	
	private ObjectFactory<T> factory;
	
	public ObjPool(int capacity,ObjectFactory<T> factory){
		this.capacity = capacity;
		this.semaphore = new Semaphore(capacity);
		this.factory = factory;
		this.head = null;
		this.tail = null;
	}
	
	//获得对象
	public T getObject() throws InterruptedException{
		semaphore.acquire();
		return getNextObj();
	}
	
	private T getNextObj(){
		lock.lock();
		try{
			if(head==null){
				T temp  = factory.genObject();
				logger.info("head is null! make obj now ");
				return temp;
			}
			Node<T> rec = head;//当前节点对象
			head = head.next;//取下一个节点作为首节点
			if(head==null) tail = null;
			rec.next = null; //help GC
			System.out.println("head is not null! get obj now ");
			return rec.obj;
		}finally{
			lock.unlock();
		}
	}
	
	public void returnObject(T obj){
		this.putObjBack(obj);
		semaphore.release();
	}
	
	private void putObjBack(T t){
		lock.lock();
		try{
			Node node = new Node();
			node.obj = t;
			if(tail==null){
				head=tail=node;
				System.out.println("head is null! return node as head.");
			}else{
				tail.next = node;
				tail = node;
				System.out.println("head is not null! return node as head.");
			}
		}finally{
			lock.unlock();
		}
	}
	
	
	
	
}

interface ObjectFactory<T>{
	public T genObject();
}

class MyObjectFactory implements ObjectFactory<String>{

	@Override
	public String genObject() {
		Random random= new Random();
		int i = random.nextInt(100);
		return "gen obj "+i;
	}
	
}


class Node<T>{
	public T obj;
	public Node next;
	
	public T getObj() {
		return obj;
	}
	public void setObj(T obj) {
		this.obj = obj;
	}
	public Node getNext() {
		return next;
	}
	public void setNext(Node next) {
		this.next = next;
	}
	public Node(T obj){
		this.obj = obj;
	}
	public Node(){
	}
}






